package midas.mw.crt.MD;

import midas.mw.cfg.CfgLogging;
import midas.mw.cfg.log.Logger;
import midas.mw.crt.common.IPMessage;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Vector;

public class TimeQueue
{
	
	/**
	 * Stores the time to live "ttl" and the identification of all the messages in the MessageDispatcher
	 */
	private Vector times;
		
	/**
	 * Constructor - Create an instance of this class.
	 * Create an TimeQueue instance and initializes the structure "times".  
	 */
	public TimeQueue ()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "TimeQueue()");		
		
		times = new Vector();
	}
	
	/**
	 * Returns true if the TimeQueue is empty.
	 * This method delegates the operation to the ArrayList "times", 
	 * just calling ArrayList.isEmpty() function.
	 * 
	 * @return true if the TimeQueue has no messages stored; false otherwise
	 */
	public boolean isEmpty()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "TimeQueue.isEmpty()");
		
		return times.isEmpty();
	}
		
	
	/**
	 * Inserts IPMessages in the TimeQueue in a sort way
	 * This function inserts an IPMessage. It's done in a sort way. The function
	 * returns whether the algorithm inserts or no the message in the TimeQueue
	 * This function is synchronized, because more than one thread can access 
	 * the TimeQueue at the same time.
	 *   
	 * @param ipMessage Message to be inserted.
	 * @return true if the message is inserted in the TimeQueue; false otherwise
	 */
	public boolean insertOrderMessage (IPMessage ipMessage)
	{
		//En este caso no hace falta sincronizar porque el unico sitio desde el que se la llama es desde
		//MessageDispatcher.enqueueMessage		
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "TimeQueue.insertOrderMessage(IPMessage)");
		
		boolean insert = false;
		ipMessage.setExpirationDate(new Date(System.currentTimeMillis() + ipMessage.getExpirationTime()));
		if (times.isEmpty())
		{			
			times.add(ipMessage);
			insert = true;
		}
		else
		{
			int counter  	= 0;
			Iterator iter 	= times.iterator();
			while (iter.hasNext())
			{
				if (((IPMessage)iter.next()).getExpirationDate().after(ipMessage.getExpirationDate()))
					break;
				counter++;
			}
			times.add(counter,ipMessage);
			insert = true;
		}
		return insert;
	}

	/**
	 * Deletes the IPMessage from the TimeQueue.
	 * This function erases a IPMessage from the TimeQueue. It returns the message
	 * that has just been deleted and if the function could not erase the message 
	 * returns null.
	 * This function is synchronized, because more than one thread can access 
	 * the TimeQueue at the same time.
	 * 
	 * @param ipMessage the message to be erased.
	 * @return The message as an IPMessage whether it is erased by the algorithm or
	 * 			null in any other case. 
	 */
	public synchronized IPMessage deleteMessage (IPMessage ipMessage)
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "TimeQueue.deleteMessage(IPMessage)");
		
		if ( times.isEmpty() || !(times.contains(ipMessage)) )
			return null;
		else
		{
			IPMessage deleteMessage = (IPMessage) times.remove(times.indexOf(ipMessage));
			return deleteMessage;
		}
	}

	/**
	 * Deletes all the expired messages from the TimeQueue.
	 * This Function tries to erase from the TimeQueue all the messages
	 * that have expired. A message have expired when it reaches its expiration time date. 
	 *  
	 * @return The list of deleted and expired messages. It is empty if no one message 
	 * 			has been erased.
	 */
	public ArrayList deleteExpiredMessages()
	{
		//En este caso no hace falta sincronizar porque el unico sitio desde el que se la llama es desde
		//MessageDispatcher.run
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "TimeQueue.deleteExpiredMessages()");
		
		ArrayList msgs = new ArrayList();;
		Iterator iter 	= times.iterator();
		boolean exit 	= false;
		IPMessage actual;
		
		while (iter.hasNext() && !(exit))
		{
			actual = (IPMessage) iter.next();
			if (actual.getExpirationDate().getTime() <= System.currentTimeMillis())
			{
				msgs.add(actual);
				deleteMessage(actual);
				iter = times.iterator();
			}
			else 
				exit = true;
		}
		return msgs;
	}
	
	
		
		
	/**
	 * Allows to access the times structure
	 * @return The times structure
	 */
	public Vector getTimes()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "TimeQueue.getTimes()");
		
		return times;
	}
}
